<!DOCTYPE html>
<html>
	<head>
		<meta charset="utf-8" />
		<title>抽象工厂模式</title>
	</head>
	<body>
		<script>
			// 模拟Java的抽象类,这是最上层
			class MobilePhoneFactory {
			    // 提供操作系统的接口
			    createOS(){
			        throw new Error("抽象工厂方法不允许直接调用，你需要将我重写！");
			    }
			    // 提供硬件的接口
			    createHardWare(){
			        throw new Error("抽象工厂方法不允许直接调用，你需要将我重写！");
			    }
			}
			// 定义操作系统这类产品的抽象产品类
			class OS {
			    controlHardWare() {
			        throw new Error('抽象产品方法不允许直接调用，你需要将我重写！');
			    }
			}
			
			// 定义具体操作系统的具体产品类
			class AndroidOS extends OS {
			    controlHardWare() {
			        console.log('我会用安卓的方式去操作硬件')
			    }
			}
			
			class AppleOS extends OS {
			    controlHardWare() {
			        console.log('我会用🍎的方式去操作硬件')
			    }
			}
			// 定义手机硬件这类产品的抽象产品类
			class HardWare {
			    // 手机硬件的共性方法，这里提取了“根据命令运转”这个共性
			    operateByOrder() {
			        throw new Error('抽象产品方法不允许直接调用，你需要将我重写！');
			    }
			}
			
			// 定义具体硬件的具体产品类
			class QualcommHardWare extends HardWare {
			    operateByOrder() {
			        console.log('我会用高通的方式去运转')
			    }
			}
			
			class MiWare extends HardWare {
			    operateByOrder() {
			        console.log('我会用小米的方式去运转')
			    }
			}
			// 具体工厂继承自抽象工厂
			class FakeStarFactory extends MobilePhoneFactory {
			    createOS() {
			        // 提供安卓系统实例
			        return new AndroidOS()
			    }
			    createHardWare() {
			        // 提供高通硬件实例
			        return new QualcommHardWare()
			    }
			}
			// 这是我的手机
			const myPhone = new FakeStarFactory()
			// 让它拥有操作系统
			const myOS = myPhone.createOS()
			// 让它拥有硬件
			const myHardWare = myPhone.createHardWare()
			// 启动操作系统(输出'我会用安卓的方式去操作硬件')
			myOS.controlHardWare()
			// 唤醒硬件(输出‘我会用高通的方式去运转’)
			myHardWare.operateByOrder();
			// 补充，如果说FakeStarFactory过时了，那么我们不需要修改他的代码，只需要新增一个类就行了。
			// 并且我们遵循开放封闭原则：对拓展开放，对修改封闭。
			// 说得更准确点，软件实体（类、模块、函数）可以扩展，但是不可修改。
			class newStarFactory extends MobilePhoneFactory {
			    createOS() {
			        // 操作系统实现代码
			    }
			    createHardWare() {
			        // 硬件实现代码
			    }
			}
		</script>
	</body>
</html>
